<?php
/**
 ******************************************************************************
 ******************************************************************************
 *          DateSimple.php
 * @package common/util
 *
 * @author  j.garcia@irobase.net
 * @date    24 déc. 07
 *
 ******************************************************************************
 */

/**
 * Contient des informations d'une date et d'une heure.
 *
 * @package common/util
 */
class DateSimple {

    private $annee;
    private $mois;
    private $jour;
    private $heure;
    private $minute;
    private $second;
    //private $milisecond;
    private $timestamp;
    
    private $estDateZero;

    /**
     * Le caractère qui sert à séparer les chiffres dans une date
     */
    const _DATE_SEPARATEUR  = '/';

    /**
     * Le caractère qui sert à séparer les chiffres de l'heure
     */
    const _HEURE_SEPARATEUR = ':';
    
    const _COMPARAISON__EGAL = 0;
    const _COMPARAISON__SUPERIEURE = 1;
    const _COMPARAISON__INFERIEURE = -1;

    const _DATE_ZERO    = 'zero';
    

    //*************************************************************************
    //*************************************************************************

    /**
     * Créé un nouveau objet DateSimple, qui inclus information de l'année, le mois et
     * le jour. N'envoyer pas de paramètres pour créer la date actuelle.
     *
     * @param string $dateString    Le format accepté est 'jj/mm/aaaa'
     * @param string $timeString
     * @return boolean      Vrai, s'il n'y a pas eu d'erreurs
     *
     * @throws Exception
     */
    public function __construct($dateString=null,$timeString=null) {
        if (($dateString == null) && ($timeString == null)) {
            //-- Créer le timestamp par défaut.
            //-- Etablit la valeur initial du timeStamp

            return $this->setTimestamp(time());
        }
        
        // date zéro !
        if ( $dateString == self::_DATE_ZERO) {
            $this->estDateZero = true;
            return;
        }

        if ($dateString != null) {
            if (strlen($dateString) <> 10) {
                // Erreur !
                throw new Exception ();
            }

            $dateArray = split(self::_DATE_SEPARATEUR, $dateString);

            $mois  = $dateArray[1];
            $jour  = $dateArray[0];
            $annee = $dateArray[2];

            if (!checkdate($mois,$jour,$annee)) {
                throw new Exception ();
            }
        }
        
        $heures  = 0;
        $minutes = 0;
        $seconds = 0;
        if ($timeString != null) {
            if (strlen($timeString) <> 8) {
                throw new Exception();
            }

            $heureArray = split(self::_HEURE_SEPARATEUR, $timeString);

            $heures  = $heureArray[0];
            $minutes = $heureArray[1];
            $seconds = $heureArray[2];

            if ( ($heures < 0) || ($heures > 23) ) {
                throw new Exception();
            }

            if ( ($minutes < 0) || ($minutes > 59) ) {
                throw new Exception();
            }

            if ( ($seconds < 0) || ($seconds > 59) ) {
                throw new Exception();
            }
        }

        return $this->setTimestamp( mktime($heures, $minutes, $seconds, $mois, $jour, $annee) );
    }
    


    /**
     * Enter description here...
     *
     * <b>Précondition : </b> L'objet $timestamp ne doit pas être <i>null</i>
     *
     * @param unknown_type $timestamp
     * @return boolean      Vrai, s'il n'y a pas eu d'erreurs
     *
     * @throws Exception
     */
    private static function validateTimestamp($timestamp) {

        //validation de la date
        $annee    = date('Y',$timestamp);
        $mois     = date('n',$timestamp);
        $jour     = date('j',$timestamp);

        if (!checkdate($mois,$jour,$annee)) {
            throw new Exception();
        }

        //validation de l'heure
        $heure    = date('G',$timestamp);
        $minute   = date('i',$timestamp);
        $second   = date('s',$timestamp);

        if ( ($heure < 0) || ($heure > 23) ) {
            throw new Exception();
        }

        if ( ($minute < 0) || ($minute > 59) ) {
            throw new Exception();
        }

        if ( ($second < 0) || ($second > 59) ) {
            throw new Exception();
        }

        return true;
    }

    public function getEstDateZero()  {
        return $this->estDateZero;
    }

    public function getAnnee() {
        return $this->annee;
    }

    public function getMois() {
        return $this->mois;
    }

    public function getJour() {
        return $this->jour;
    }

    public function getHeure() {
        return $this->heure;
    }

    public function getMinute() {
        return $this->minute;
    }

    public function getSecond() {
        return $this->second;
    }

    /**
     * Enter description here... 
     * @param $newJour
     * @param $newMois
     * @param $newAnnee
     * @return boolean      Vrai, s'il n'y a pas eu d'erreurs,
     *                      False, si l'objet est la date zéro.
     */
    public function modifier($newJour=null, $newMois=null, $newAnnee=null) {

        if ($this->estDateZero) return false;
        
        $tempJour   = ($newJour !== null) ? $newJour : $this->jour;
        $tempMois   = ($newMois !== null) ? $newMois : $this->mois;
        $tempAnnee  = ($newAnnee !== null) ? $newAnnee : $this->annee;
        
        if (!checkdate($tempMois,$tempJour,$tempAnnee)) {
            throw new Exception ();
        }

        $this->annee  = $tempAnnee;
        $this->mois   = $tempMois;
        $this->jour   = $tempJour;

        return true;
    }
    

    /**
     * 
     * @param DateSimple $uneAutreDate
     * @param $doComparerHeureAussi
     * @return bool
     */
    public function estEgale(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {
        
        if ($this->comparerDate($uneAutreDate, $doComparerHeureAussi) == self::_COMPARAISON__EGAL)
            return true;
            
        return false;
    }
    
    /**
     * 
     * @param DateSimple $uneAutreDate
     * @param $doComparerHeureAussi
     * @return bool
     */
    public function estSuperieure(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {
        
        if ($this->comparerDate($uneAutreDate, $doComparerHeureAussi) == self::_COMPARAISON__SUPERIEURE)
            return true;
            
        return false;
    }
    
    /**
     * 
     * @param DateSimple $uneAutreDate
     * @param $doComparerHeureAussi
     * @return bool
     */
    public function estSuperieureOuEgale(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {
        $result = $this->comparerDate($uneAutreDate, $doComparerHeureAussi);

        if ($result == self::_COMPARAISON__EGAL)
            return true;

        if ($result == self::_COMPARAISON__SUPERIEURE)
            return true;

        return false;
    }


    /**
     * 
     * @param DateSimple $uneAutreDate
     * @param $doComparerHeureAussi
     * @return bool
     */
    public function estInferieure(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {
        
        if ($this->comparerDate($uneAutreDate, $doComparerHeureAussi) == self::_COMPARAISON__INFERIEURE)
            return true;
            
        return false;
    }
    
    
    /**
     * 
     * @param DateSimple $uneAutreDate
     * @param $doComparerHeureAussi
     * @return bool
     */
    public function estInferieureOuEgale(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {
        $result = $this->comparerDate($uneAutreDate, $doComparerHeureAussi);

        if ($result == self::_COMPARAISON__EGAL)
            return true;

        if ($result == self::_COMPARAISON__INFERIEURE)
            return true;

        return false;
    }



    /**
     * Fait une comparaison entre cet objet Date et un autre objet, passé para parametre
     * Retourne une exception si l'objet passé par paramètre est null ou s'il n'est pas
     * un objet date valide.
     *
     * @deprecated Utiliser plutôt : @see classes/common/util/DataSimple#estSuperieure(), 
     *      @see classes/common/util/DataSimple#estInferieure()
     * 
     * @param DateSimple $uneAutreDate
     *
     * @return int         Les résultat obtenu est un des suivants :
     * <ul>
     * <li>_COMPARAISON__EGAL; : Si sont égales</li>
     * <li>_COMPARAISON__SUPERIEURE : Si la date de cet objet est supérieure</li>
     * <li>_COMPARAISON__INFERIEURE : Si la date de cet objet est inférieure</li>
     * </ul>
     *
     * @throws Exception
     */
    public function comparerDate(DateSimple & $uneAutreDate, $doComparerHeureAussi=false) {

        // si zéro == zéro !
        if ( ($this->estDateZero) and ($uneAutreDate->getEstDateZero() ) ) return self::_COMPARAISON__EGAL;
        
        
        $date1 = $this->afficherDate();
        $date2 = $uneAutreDate->afficherDate();
        
        // par défaut, l'heure est à zéro ! 
        $date1Int = mktime(0,0,0,$this->getMois(), $this->getJour(), $this->getAnnee()) ;
        $date2Int = mktime(0,0,0,$uneAutreDate->getMois(), $uneAutreDate->getJour(), $uneAutreDate->getAnnee()) ;
        
        if ($doComparerHeureAussi) {
            $date1Int = $this->getTimestamp();
            $date2Int = $uneAutreDate->getTimestamp();
        }
        
        
        if ($date1Int > $date2Int) {
            return self::_COMPARAISON__SUPERIEURE;
        }
        
        if ($date1Int < $date2Int) {
            return self::_COMPARAISON__INFERIEURE;
        }
        

        return self::_COMPARAISON__EGAL;
    }


    /**
     * Affiche la date de l'objet passé par paramètre, avec le format "jj/mm/aaaa".
     *
     * @return String      Date, avec le format "dd/mm/aaaa"
     */
    public function afficherDate() {
        return sprintf('%02d%4$s%02d%4$s%04d', $this->jour, $this->mois, $this->annee, self::_DATE_SEPARATEUR);
    }
    
    /**
     * Affiche la date et l'heure de l'objet passé par paramètre, avec le format "jj/mm/aaaa hh:mm".
     *
     * @return String      Date, avec le format "dd/mm/aaaa"
     */
    public function afficherDateTime() {
        return $this->afficherDate() . ' ' . sprintf('%02d%3$s%02d', $this->heure, $this->minute, self::_HEURE_SEPARATEUR);
    }

    /**
     * Affiche la date de l'objet passé par paramètre, avec le format "jj/mm/aaaa".
     *
     * @return String      Date, avec le format "dd/mm/aaaa"
     */
    public function __toString() {
        return $this->afficherDate();
    }
    
    
    /**
     * @todo Enter description here...
     *
     * @return unknown
     */
    public function getTimestamp() {
        return $this->timestamp;
    }
    
    
    /**
     * @todo Enter description here...
     *
     */
    private function setTimestamp($timestamp) {

        // if validateTimestamp = true, continue, sinon, erreur !
        $this->validateTimestamp($timestamp);


        $this->timestamp    = $timestamp;
        $currentTimestamp   = $timestamp;

        $annee    = date('Y',$currentTimestamp);
        $mois     = date('n',$currentTimestamp);
        $jour     = date('j',$currentTimestamp);

        $heure    = date('G',$currentTimestamp);
        $minute   = date('i',$currentTimestamp);
        $second   = date('s',$currentTimestamp);

        $this->annee  = $annee;
        $this->mois   = $mois;
        $this->jour   = $jour;
        $this->heure  = $heure;
        $this->minute = $minute;
        $this->second = $second;

        return true;
    }
    
    
    
    /**
     * Copie l'information de  l'objet DateSimple passé par paramètre
     *
     * @param Datesimple $uneAutreDate
     * @return bool
     */
    public function copy(Datesimple & $uneAutreDate) {
        return $this->setTimestamp($uneAutreDate->getTimestamp());
    }


    /** 
     * @todo Enter description here... 
     * Utilise mktime pour calculer le nouveau timestamp...
     *  
     * @param unknown_type $monthsToAdd
     * @return boolean      Vrai, s'il n'y a pas eu d'erreurs,
     *                      False, si l'objet est la date zéro.
     */
    public function addMonth($monthsToAdd) {
        
        if ($this->estDateZero) return false;
        
        $nouveauMois = $this->mois+$monthsToAdd;

        $this->setTimestamp(
            mktime($this->heure, $this->minute, $this->second, $nouveauMois, $this->jour, $this->annee)
        );
        
        return true;
    }

}
?>